#include "streambuffer.h"

#include <QDebug>
#include <QMutexLocker>
#include <QDir>

StreamBuffer::StreamBuffer(const QString& streamName, int size):
        QIODevice(),
        cacheFile(QDir::temp().absoluteFilePath(streamName)),
        contentLength(size),
        readPos(0),
        writePos(0)
{
    startTimer(100);
}

StreamBuffer::~StreamBuffer()
{
    qDebug() << "Closing buffer " << cacheFile.fileName();
    cacheFile.close();
    cacheFile.remove();
}

bool StreamBuffer::atEnd() const
{
    //qDebug() << "StreamBuffer::atEnd";
    QMutexLocker locker(&lock);
    return readPos >= contentLength; //size();
}

qint64 StreamBuffer::bytesAvailable() const
{
    qDebug() << "StreamBuffer::bytesAvailable";
    QMutexLocker locker(&lock);
    return qMax(qint64(0), contentLength /*writePos*/ - readPos);
}

qint64 StreamBuffer::bytesToWrite() const
{
    qDebug() << "StreamBuffer::bytesToWrite";
    QMutexLocker locker(&lock);
    return cacheFile.bytesToWrite();
}

bool StreamBuffer::canReadLine() const
{
    qDebug() << "StreamBuffer::canReadLine";
    return false;
}

void StreamBuffer::close()
{
    qDebug() << "StreamBuffer::close";
    QMutexLocker locker(&lock);
    QIODevice::close();
    cacheFile.close();
}

//bool StreamBuffer::isSequential() const
//{
//    qDebug() << "StreamBuffer::isSequential";
//    return false;
//}

bool StreamBuffer::open(OpenMode mode)
{
    qDebug() << "StreamBuffer::open " << mode;
    QMutexLocker locker(&lock);
    bool ret = QIODevice::open(mode);
    readPos = 0;
    return ret && (cacheFile.isOpen() ||
                   cacheFile.open(QIODevice::ReadWrite|QIODevice::Unbuffered));
}

qint64 StreamBuffer::pos() const
{
    qDebug() << "StreamBuffer::pos -> " << readPos;
    QMutexLocker locker(&lock);
    return readPos;
}

bool StreamBuffer::reset()
{
    qDebug() << "StreamBuffer::reset";
    QMutexLocker locker(&lock);
    readPos = 0;
    //writePos = 0;
    //return cacheFile.reset();
    return true;
}

bool StreamBuffer::seek(qint64 pos)
{
    qDebug() << "StreamBuffer::seek " << pos;
    QMutexLocker locker(&lock);
    readPos = pos;
    return true;
}

qint64 StreamBuffer::size() const
{
    //qDebug() << "StreamBuffer::size -> " << /*writePos;*/ contentLength;
    return contentLength; //writePos;
}

//bool StreamBuffer::waitForBytesWritten(int msecs) // REMOVE
//{
//    return false;
//}
//
//bool StreamBuffer::waitForReadyRead (int msecs) // REMOVE
//{
//    return false;
//}

qint64 StreamBuffer::readData(char* data, qint64 maxSize)
{
    QMutexLocker locker(&lock);

    // read past cached data, return block of 0's
    if (readPos > writePos) {
        //qDebug() << "Read past buffer!";
        //memset(data, 0, maxSize);
        //return maxSize;
        return -1;
    }
    // limit number of bytes to what is available
    if (readPos + maxSize > writePos) {
        qDebug() << "Read last available chunk! r=" << readPos << " w=" << writePos << " m=" << maxSize;
        maxSize = writePos - readPos;
        //return -1;
    }
    cacheFile.seek(readPos);
    qint64 n = cacheFile.read(data, maxSize);
    qDebug() << "read " << n << " bytes";
    if (n > 0)
        readPos += n;
    //qDebug() << "StreamBuffer::readData " << maxSize << " -> " << n;
    return n;
}

qint64 StreamBuffer::writeData(const char* data, qint64 maxSize)
{
    QMutexLocker locker(&lock);
    cacheFile.seek(writePos);
    qint64 n = cacheFile.write(data, maxSize);
    if (n > 0)
        writePos += n;
    else
        qDebug() << "Write failed";
    //cacheFile.flush();
    //qDebug() << "StreamBuffer::writeData " << maxSize << " -> " << n;
    emit readyRead();
    return n;
}

void StreamBuffer::timerEvent(QTimerEvent* event)
{
    qDebug() << "readPos=" << readPos << " writePos=" << writePos << " size=" << size();
}
